package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.constants.WmNewsConstants;
import com.heima.common.constants.WmNewsMessageConstants;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.NewsAuthDto;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.model.wemedia.vo.WmNewsVo;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import com.heima.wemedia.service.WmUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j//Lombok注解，用于生成日志记录器（Logger）
@Transactional//事务注解，开启事务，保证数据一致性，事务失败回滚，事务成功提交
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

	@Autowired
	private WmNewsTaskService wmNewsTaskService;

	/**
	 * 查询自媒体文章
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult findAll(WmNewsPageReqDto dto) {

		//1.检查参数，检查前端传递的类是否为null
		if (dto == null) {
			//如果为null，直接提示参数不合法
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		//分页参数检查, 这个方法是PageRequestDto中的方法，继承该类的类中可以调用
		dto.checkParam();

		//如果threadlocal可以获取当前登录人的信息
		WmUser user = WmThreadLocalUtil.getUser();
		//判断当前用户是否为空
		if (user == null) {
			//如果为空的话，需要提示需要登录
			return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
		}

		//2.分页条件查询，创建一个Page对象，将当前分页和每页大小赋值给当前对象
		IPage page = new Page(dto.getPage(), dto.getSize());
		//构建条件查询器，该查询器是用来对WmNews进行操作的
		LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
		//状态精确查询,需要根据文章的状态进行查询
		if (dto.getStatus() != null) {
			//增加条件，查找和前端传递的状态一样的文章状态
			lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus());
		}

		//频道精确查询，这里获取频道
		if (dto.getChannelId() != null) {
			//查找符合前端传递的频道下的所有文章
			lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
		}

		//时间范围查询
		if (dto.getBeginPubDate() != null && dto.getEndPubDate() != null) {
			//查找发布时间在前端传递的开始时间和结束时间之间的所有文章
			lambdaQueryWrapper.between(WmNews::getPublishTime, dto.getBeginPubDate(), dto.getEndPubDate());
		}

		//关键字模糊查询,如果前端传递的关键字不为空的话，需要将其作为查询条件的一部分
		if (StringUtils.isNotBlank(dto.getKeyword())) {
			//通过前端传递的关键字在文章中进行模糊匹配
			lambdaQueryWrapper.like(WmNews::getTitle, dto.getKeyword());
		}

		//查询当前登录用户的文章,当前用户只能查询当前用户的信息
		lambdaQueryWrapper.eq(WmNews::getUserId, user.getId());

		//发布时间倒序查询，查询到的数据要根据时间排序，时间越新排序在最上面
		lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);

		//将分页信息和条件构造器传入
		page = page(page, lambdaQueryWrapper);

		//3.结果返回,创建一个统一封装结果集，然后将当前页码，每页大小，所有数据带入
		ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
		//将所有数据返回（这里的数据是指符合上述要求的数据）
		responseResult.setData(page.getRecords());

		//最后将统一封装结果集进行返回
		return responseResult;
	}

	@Autowired
	public WmNewsAutoScanService wmNewsAutoScanService;

	/**
	 * 发布修改文章或保存为草稿
	 *
	 * @param dto
	 * @return
	 */
	@Override
	//WmNewsDto类是对前端传递的参数的封装类
	public ResponseResult submitNews(WmNewsDto dto) {

		//0.条件判断，一般都需要对前端传递的参数做校验，提高系统的健壮性
		//如果前端传递的参数为空或者是对象的内容为空，则返回参数错误
		if (dto == null || dto.getContent() == null) {
			//封装返回结果，用枚举常量表示错误类型为非法参数
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		//1.保存或修改文章,首先创建一个WmNews文章对象，用来接收前端传递的参数
		WmNews wmNews = new WmNews();
		//属性拷贝 属性名和类型相同才能拷贝，否则会报错
		BeanUtils.copyProperties(dto, wmNews);

		//封面图片  list---> string
		//对于图片这个属性，前端传过来是一个list，所以需要把list转换成字符串，再保存到数据库中
		if (dto.getImages() != null && dto.getImages().size() > 0) {
			//[1dddfsd.jpg,sdlfjldk.jpg]-->   1dddfsd.jpg,sdlfjldk.jpg
			//这一步的作用是把图片列表转换成字符串，以逗号分隔
			//dto.getImages()是一个List<String>类型的集合，其中存储了图片的 URL 地址
			//StringUtils.join()方法可以把list中的元素按照指定的分隔符拼接成一个字符串
			String imageStr = StringUtils.join(dto.getImages(), ",");
			//将拼接后的字符串imageStr设置到WmNews对象的images属性中
			wmNews.setImages(imageStr);
		}

		//如果当前封面类型为自动 -1    文章封面类型  0 无图 1 单图 3 多图 -1 自动
		//这里定义了一个WemediaConstants类，里面定义了一些常量，其中WM_NEWS_TYPE_AUTO的值为-1，表示自动
		//这样的好处是避免硬编码，提高代码的优雅性
		if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
			//如果类型为字段的话，则将文章类型设置为null，表示自动匹配封面类型
			//这里的逻辑是，如果前端传递的文章类型为-1，则表示自动匹配封面类型，此时将文章类型设置为null，由后台自动匹配
			wmNews.setType(null);
		}

		//定义方法，用来判断传入的WmNews对象是否包含id来判断是创建新文章还是更新已有文章
		saveOrUpdateWmNews(wmNews);

		//2.判断是否为草稿  如果为草稿结束当前方法
		//用前端传入的dto的状态和枚举类中的状态对比，如果一样说明文章的状态是草稿，则直接返回成功
		if (dto.getStatus().equals(WmNews.Status.NORMAL.getCode())) {
			//如果是草稿的话，可以暂时不用保存图文和素材信息关系
			return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
		}

		//3.不是草稿，保存文章内容图片与素材的关系
		//获取到文章内容中的图片信息
		List<String> materials = ectractUrlInfo(dto.getContent());

		//保存文章内容图片与素材的关系
		saveRelativeInfoForContent(materials, wmNews.getId());

		//4.不是草稿，保存文章封面图片与素材的关系，如果当前布局是自动，需要匹配封面图片
		saveRelativeInfoForCover(dto, wmNews, materials);

		//审核文章
		//wmNewsAutoScanService.autoScanWmNews(wmNews.getId());
		wmNewsTaskService.addNewsToTask(wmNews.getId(), wmNews.getPublishTime());

		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

	}

	/**
	 * 第一个功能：如果当前封面类型为自动，则设置封面类型的数据
	 * 匹配规则：
	 * 1，如果内容图片大于等于1，小于3  单图  type 1
	 * 2，如果内容图片大于等于3  多图  type 3
	 * 3，如果内容没有图片，无图  type 0
	 * <p>
	 * 第二个功能：保存封面图片与素材的关系
	 *
	 * @param dto
	 * @param wmNews
	 * @param materials
	 */
	private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {

		List<String> images = dto.getImages();

		//如果当前封面类型为自动，则设置封面类型的数据
		if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)) {
			//多图
			if (materials.size() >= 3) {
				wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
				images = materials.stream().limit(3).collect(Collectors.toList());
			} else if (materials.size() >= 1 && materials.size() < 3) {
				//单图
				wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
				images = materials.stream().limit(1).collect(Collectors.toList());
			} else {
				//无图
				wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
			}

			//修改文章
			if (images != null && images.size() > 0) {
				wmNews.setImages(StringUtils.join(images, ","));
			}
			updateById(wmNews);
		}
		if (images != null && images.size() > 0) {
			saveRelativeInfo(images, wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);
		}

	}


	/**
	 * 处理文章内容图片与素材的关系
	 *
	 * @param materials
	 * @param newsId
	 */
	private void saveRelativeInfoForContent(List<String> materials, Integer newsId) {
		saveRelativeInfo(materials, newsId, WemediaConstants.WM_CONTENT_REFERENCE);
	}

	@Autowired
	private WmMaterialMapper wmMaterialMapper;

	/**
	 * 保存文章图片与素材的关系到数据库中
	 *
	 * @param materials
	 * @param newsId
	 * @param type
	 */
	//materials保存的是图片url，newsId是新闻id
	//该方法用于保存文章内容图片与素材的关系，或者封面图片与素材的关系
	//Short type: 参数，表示素材引用的类型。例如，文章内容图片或封面图片
	private void saveRelativeInfo(List<String> materials, Integer newsId, Short type) {
		//只有当materials有内容时才需要需要进行保存操作
		if (materials != null && !materials.isEmpty()) {
			//通过图片的url查询素材的id
			//创建了一个查询条件，用于查找 WmMaterial 表中 url 字段值在 materials 列表中的所有记录
			List<WmMaterial> dbMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, materials));

			//检查 dbMaterials 是否为 null 或者是否为空
			if (dbMaterials == null || dbMaterials.size() == 0) {
				//手动抛出异常   第一个功能：能够提示调用者素材失效了，第二个功能，进行数据的回滚
				//如果素材为空或者是大小为0，抛出业务异常，提示自媒体文章引用失败
				throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
			}

			//判断材料列表与数据库查询结果数量是否一致
			if (materials.size() != dbMaterials.size()) {
				throw new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
			}

			List<Integer> idList = dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

			//批量保存
			wmNewsMaterialMapper.saveRelations(idList, newsId, type);
		}
	}


	/**
	 * 提取文章内容中的图片信息
	 *
	 * @param content
	 * @return
	 */
	private List<String> ectractUrlInfo(String content) {
		//定义一个List集合来存储文章内容中的图片信息
		List<String> materials = new ArrayList<>();

		//解析文章内容，获取图片信息前端传递过来的是json数据，转换成map
		//假设content是一个JSON数组字符串，例如：[{"type": "image", "value": "http://example.com/image.jpg"}, {"type": "text", "value": "Hello World"}]
		//解析后的maps是一个包含多个Map对象的列表，每个Map对象代表一个JSON对象
		List<Map> maps = JSON.parseArray(content, Map.class);
		//遍历解析后的Map对象
		for (Map map : maps) {
			//检查type键的值是否为"image"，如果是，说明这是一个图片内容
			if (map.get("type").equals("image")) {
				//获取图片的url
				String imgUrl = (String) map.get("value");
				//将图片的url添加到List集合中
				materials.add(imgUrl);
			}
		}

		return materials;
	}

	@Autowired
	private WmNewsMaterialMapper wmNewsMaterialMapper;

	/**
	 * 保存或修改文章
	 *
	 * @param wmNews
	 */
	//根据传入的WmNews对象是否包含id来判断是创建新文章还是更新已有文章
	private void saveOrUpdateWmNews(WmNews wmNews) {
		// 补充属性
		//根据threadlocal来填充当前用户id
		wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
		//补充创建时间和提交时间
		wmNews.setCreatedTime(new Date());
		wmNews.setSubmitedTime(new Date());
		//给文章设置是否上架
		wmNews.setEnable((short) 1);//默认上架

		//id属性是用来判断是创建新文章还是更新已有文章
		if (wmNews.getId() == null) {
			//当前文章对象没有id属性，即为保存，即创建新文章（id是需要插入数据库中自动生成的）
			//调用MP的save方法保存文章对象
			save(wmNews);
		} else {
			//如果文章有id，表示是修改操作
			//我们的逻辑是先删除原有的图片与素材的关系，然后再保存新的图片与素材的关系（先删除，再新增，达到更新的目的）
			//这样的好处是，如果前端传过来的图片与素材的数量发生变化，则可以更新数据库中的图片与素材的关系
			wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
			//调用MP的保存方法，即根据id更新已有文章
			updateById(wmNews);
		}
	}


	@Autowired
	private WmNewsMapper wmNewsMapper;

	/**
	 * 根据id查询文章
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ResponseResult detail(Integer id) {
		//首先对参数进行校验
		if (id == null) {
			//如果参数为空，直接抛出异常，提示无效参数
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		//根据id查询文章
		WmNews wmNews = wmNewsMapper.selectById(id);
		//判断文章是否存在
		if (wmNews == null) {
			//如果文章不存在，则返回数据不存在的提示
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
		}
		//如果通过了上述判断，则说明文章存在，可以返回文章数据给前端进行渲染展示
		return ResponseResult.okResult(wmNews);
	}

	/**
	 * 删除文章
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ResponseResult delNews(Integer id) {
		//首先进行参数校验，判断前端传递的参数是否为空
		if (id == null) {
			//如果参数为空，则抛出异常，提示无效参数
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章id不可缺少");
		}

		//根据id查询文章
		WmNews wmNews = wmNewsMapper.selectById(id);
		//判断文章是否存在，只有存在才可以进行删除操作
		if (wmNews == null) {
			//如果文章不存在，则返回数据不存在的提示
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
		}

		//判断文章是否已发布，只有未发布的文章才可以进行删除操作
		if (wmNews.getStatus().equals(WmNews.Status.PUBLISHED.getCode())) {
			//如果文章已发布，则不能进行删除操作，提示参数非法，已发布的文章不能删除
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章已发布不能删除");
		}

		//程序允许到这里，说明文章存在且未发布，可以进行删除操作
		//删除wm_news表的数据
		wmNewsMapper.deleteById(id);
		//判断在news_material中是否有关联数据，如果有，则一并删除
		//创建一个LambdaQueryWrapper对象，用于查询news_material表的数据
		LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
		//设置查询条件，查询条件为文章id
		queryWrapper.eq(WmNewsMaterial::getNewsId, id);
		//根据queryWrapper条件查询news_material表的数据，并统计数量
		Integer count = wmNewsMaterialMapper.selectCount(queryWrapper);
		//判断查询结果是否大于0，如果大于0，说明有关联数据，则一并删除
		if (count > 0) {
			//有则一并删除，根据queryWrapper条件删除news_material表的数据
			wmNewsMaterialMapper.delete(queryWrapper);
		}
		//返回成功的提示
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}

	//注入kafka服务模板类,自媒体上下架成功后，会通过kafka发送给消息给文章模块
	//文章模块在监听到自媒体模块的上下架操作后，会异步将指定文章上下架操作
	//业务模块依赖于common公共模块，所以业务模块可以使用公共模块中的kafka依赖（依赖传递）
	@Autowired
	private KafkaTemplate<String, String> kafkaTemplate;

	/**
	 * 文章上下架
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult downOrUp(WmNewsDto dto) {

		//打印日志，查看是否调用了该方法
		log.info("文章{}正在执行上架/下架", dto.getId());

		//判断id是否为空，这是文章id
		if (dto.getId() == null) {
			//如果id为空，则抛出异常，提示参数错误
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章id不可缺少");
		}

		//判断有无数据，根据id查询文章，一般从数据库中查询的Java对象，我们会以DB结尾，表示数据库对象
		WmNews wmNewsDB = wmNewsMapper.selectById(dto.getId());
		//判断文章是否存在
		if (wmNewsDB == null) {
			//如果文章不存在，则返回数据不存在的提示
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
		}

		//判断是否已发布，根据数据库的对象wmNewsDB查看是否发布
		if (wmNewsDB.getStatus() != WmNews.Status.PUBLISHED.getCode()) {
			//如果文章未发布，则不能进行上下架操作，提示参数错误
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "文章未发布不能上架");
		}

		//判断是上架还是下架 -> 0：下 1：上
		if (wmNewsDB.getEnable() == 0) {
			//如果文章已下架，则将enable设置为1，表示上架
			wmNewsDB.setEnable((short) 1);
		} else if (wmNewsDB.getEnable() == 1) {
			//如果文章已上架，则将enable设置为0，表示下架
			wmNewsDB.setEnable((short) 0);
		}
		//修改数据库中的数据
		updateById(wmNewsDB);

		//发送消息，通知article端修改文章配置
		//这一步是通过kafka，通知文章模块进行数据变更
		//因为当前自媒体模块属于业务模块的子模块，业务模块中导入了common模块，
		//common模块中引入了kafka依赖，所以可以直接使用kafkaTemplate（这是依赖传递）
		//这行代码首先检查从数据库中查询到的文章对象wmNewsDB是否包含articleId属性，即是否为空
		if (wmNewsDB.getArticleId() != null) {
			//不为空，表示有数据，就创建一个新的HashMap实例，用于存储要发送的消息内容
			Map<String, Object> map = new HashMap<>();
			//给map中添加一个键值对，即将当前文章id和是否上架属性进行封装，然后打包给文章模块
			map.put("articleId", wmNewsDB.getArticleId());
			map.put("enable", dto.getEnable());
			//使用kafkaTemplate发送消息到Kafka指定的主题WM_NEWS_UP_OR_DOWN_TOPIC
			//这个常量定义了Kafka的主题名称，该主题用于文章的上下架状态更改通知
			//将消息发送到Kafka，接收方（文章模块）可以通过监听该主题来获取文章状态的更改信息
			kafkaTemplate.send(WmNewsMessageConstants.WM_NEWS_UP_OR_DOWN_TOPIC, JSON.toJSONString(map));
		}

		log.info("文章{}执行上架/下架成功", dto.getId());

		//返回成功的提示
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}

	/**
	 * 查询（待审核）文章列表
	 *
	 * @param dto
	 * @return
	 */
	@Override
	public ResponseResult findList(NewsAuthDto dto) {
		// 1. 参数检查，给page和size设置默认值，防止极端的情况
		//checkParam() 方法主要用于确保这些参数的有效性，例如检查分页参数是否合理等
		dto.checkParam();

		// 2. 记录当前页,获取了 NewsAuthDto 对象中的当前页码，并将其存储在 currentPage 变量中
		int currentPage = dto.getPage();

		// 3. 分页查询 + count查询
		//将 dto.getPage() 减1后乘以每页大小 dto.getSize()，并将结果重新设置到 dto.setPage() 中
		//这样做的目的是为了计算出数据库查询的起始位置，例如：当前页码为2，每页大小为10，则起始位置为（2-1）*10=10，即从第11条记录开始查询
		dto.setPage((dto.getPage() - 1) * dto.getSize());

		//调用 wmNewsMapper.findListAndPage(dto) 方法查询待审核的文章列表，并统计总数
		//将结果存储在 wmNewsVoList 变量中。WmNewsVo 是一个视图对象（VO），用于将查询到的数据以特定格式传递给前端
		List<WmNewsVo> wmNewsVoList = wmNewsMapper.findListAndPage(dto);
		//调用 wmNewsMapper.findListCount(dto) 方法获取待审核文章的总数
		int count = wmNewsMapper.findListCount(dto);

		// 4. 结果返回
		//根据查询到的文章总数 count 和传入的页码 currentPage 以及每页大小 dto.getSize()
		//计算出总页数，并封装到 PageResponseResult 对象中，返回给前端
		ResponseResult responseResult = new PageResponseResult(currentPage, dto.getSize(), count);
		//将查询到的文章列表 wmNewsVoList 封装到 PageResponseResult 对象中，并返回给前端
		responseResult.setData(wmNewsVoList);
		//返回 responseResult 对象，该对象包含了分页信息以及具体的文章列表数据
		return responseResult;
	}

	@Autowired
	private WmUserService wmUserService;

	/**
	 * 查询文章详情
	 *
	 * @param id
	 * @return
	 */
	@Override
	public ResponseResult findWmNewsVo(Integer id) {
		//首先检查参数，参数为空，提示报错
		if (id == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}
		//根据id查询文章信息
		WmNews wmNews = getById(id);
		if (wmNews == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
		}
		//将文章信息表WmNews赋值给WmNewsVo
		WmNewsVo wmNewsVo = new WmNewsVo();
		BeanUtils.copyProperties(wmNews, wmNewsVo);
		//根据WmNewsVo的user_id字段去作者表中查询作者名字，赋值给WmNewsVo的authorName属性
		WmUser wmUser = wmUserService.getById(wmNews.getUserId());
		wmNewsVo.setAuthorName(wmUser.getName());
		//将WmNewsVo返回给前端，供前端渲染
		return ResponseResult.okResult(wmNewsVo);
	}

	/**
	 * 文章审核，修改状态
	 *
	 * @param status 2审核失败 4审核成功
	 * @param dto
	 * @return
	 */
	@Override
	//主要功能是更新自媒体文章的状态，并在文章审核通过的情况下，将文章同步到APP端，确保APP用户能够看到审核通过的文章
	public ResponseResult updateByStatus(Short status, NewsAuthDto dto) {
		// 1. 检查参数, 首先检查传入的NewsAuthDto对象是否为null，以及该对象中的id属性是否也为null
		if (dto == null || dto.getId() == null) {
			//如果参数无效，返回错误信息PARAM_INVALID
			return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
		}

		// 2. 查询文章信息,根据传入的id查询具体的自媒体文章信息
		WmNews wmNews = getById(dto.getId());
		//确认文章是否存在,如果文章不存在，返回错误信息DATA_NOT_EXIST
		if (wmNews == null) {
			return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
		}

		// 3. 修改文章的状态,修改查询到的文章的状态为传入的status值
		wmNews.setStatus(status);
		//检查NewsAuthDto对象中的msg属性是否非空
		//StringUtils.isNotBlank(dto.getMsg())：用于检查字符串是否不为空且不包含只有空白字符的情况
		if (StringUtils.isNotBlank(dto.getMsg())) {
			//如果msg非空，则将其设置为文章的reason属性
			wmNews.setReason(dto.getMsg());
		}
		//将更新后的文章信息保存到数据库中
		updateById(wmNews);

		// 4. 审核成功，则要创建app端文章数据，并修改自媒体文章
		//在文章审核通过后，将其同步到APP端，使APP用户能够看到该文章
		if (status.equals(WemediaConstants.WM_NEWS_AUTH_PASS)) {
			// 创建app端文章数据
			ResponseResult responseResult = wmNewsAutoScanService.saveAppArticle(wmNews);
			//如果创建成功
			if (responseResult.getCode().equals(200)) {
				//将APP端生成的文章ID设置到自媒体文章的articleId属性
				wmNews.setArticleId((Long) responseResult.getData());
				//更新自媒体文章的状态为已发布（PUBLISHED），最后再次保存到数据库中
				wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
				//更新数据
				updateById(wmNews);
			}
		}

		// 5. 结果返回,通知调用者，文章状态更新操作成功
		return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
	}
}